Retirement fund
1. 题目
1.1
This retirement fund is what economists call a commitment device. I’m trying to make sure I hold on to 1 ether for retirement.
I’ve committed 1 ether to the contract below, and I won’t withdraw it until 10 years have passed. If I do withdraw early, 10% of my ether goes to the
beneficiary
(you!).I really don’t want you to have 0.1 of my ether, so I’m resolved to leave those funds alone until 10 years from now. Good luck!
翻译:
这个退休基金就是经济学家所说的承诺机制。我正在努力确保我在退休时保留 1 个以太币。
我已经向下面的合约承诺了 1 个以太币,并且在 10 年过去之前我不会撤回它。如果我提早退出,我的 10% 的以太币会流向
beneficiary
(你!)。我真的不想让你拥有我的 0.1 个以太币,所以我决定在 10 年后再单独使用这些资金。祝你好运!
1.2 源码:
1 | pragma solidity ^0.4.21; |
2.分析
- 2.1 题目的要求是将合约的钱全部取走,而不是取走合约所有者剩下的那 0.1 ether
- 2.2 所以我们将重点关注
collectPenalty
函数,成功执行msg.sender.transfer(address(this).balance);
这行代码;而要执行这行代码执行要通过两个校验。校验一:require(msg.sender == beneficiary);
验证你是否是受益人, 校验二:withdrawn = startBalance - address(this).balance > 0
验证合约所有者是否提前取款了,提前取款就可以往下执行 - 2.3 但是我们可以通过下溢的方法让 withdrawn 的值大 0,就是让
address(this).balance
的值大于 1ehter,而合约中没有可以接收主币的函数,这就需要我们使用selfdestruct
命令,将某个合约的钱强行转给指定合约 - 2.4 所以我们可以编写一个攻击合约,往合约中发送一点主币,再执行自毁命令
- 攻击合约:
1 | contract Hack { |
3.解题
3.1 部署
RetirementFundChallenge
合约
3.2 部署
Hack
合约,给RetirementFundChallenge
合约 转入 1 ether
3.3 调用 collecPenalt函数

查看isComplete的值变成了 true

一段时间之后的二刷
攻击合约
1 | /** |